home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
program
/
ppl4p10.zip
/
XYPACKET.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-02-20
|
12KB
|
434 lines
(**********************************************)
(* Copyright (C) 1995 by *)
(* MarshallSoft Computing, Inc. *)
(**********************************************)
{ $DEFINE DEBUG}
{$I DEFINES.PAS}
unit xypacket;
interface
uses config,crt,term_io,crc16,hex_io,file_io,PCL4P;
Function TxPacket(Port:Integer;
PacketNbr:Word;
PacketSize:Word;
Var Buffer:BufferType;
NCGbyte:Byte):Boolean;
Function RxPacket(Port:Integer;
PacketNbr:Word;
Var PacketSize:Word;
Var Buffer:BufferType;
NCGbyte:Byte;
Var EOTflag:Boolean):Boolean;
Function RxStartup(Port:Integer;
Var NCGbyte:Byte):Boolean;
Function TxStartup(Port:Integer;
Var NCGbyte:Byte):Boolean;
Function TxEOT(Port:Integer):Boolean;
implementation
const MAXTRY = 3;
LIMIT = 20;
const SOH = $01;
STX = $02;
EOT = $04;
ACK = $06;
NAK = $15;
CAN = $18;
procedure TimeoutMsg(Message:String;Packet:Word);
begin
WriteIntMsg('Timed out for '+Message+'. Packet ',Packet)
end;
Function TxPacket(Port:Integer; (* Port # [0..3] *)
PacketNbr:Word; (* Packet # [0,1,2,...] *)
PacketSize:Word; (* Packet size [128,1024] *)
Var Buffer:BufferType; (* 1K character buffer *)
NCGbyte:Byte) (* NAK, 'C', or 'G' *)
: Boolean; (* successfull *)
Var
I : Integer;
Code : Integer;
CheckSum : Word;
Attempt : Word;
PacketType: Byte;
Begin
(* better be 128 or 1024 packet length *)
case PacketSize of
128: PacketType := SOH;
1024: PacketType := STX;
else
begin
WriteLn('Bad packet size!');
TxPacket := FALSE;
exit
end;
end; (* case *)
PacketNbr := PacketNbr and $00ff;
(* make up to MAXTRY attempts to send this packet *)
for Attempt := 1 to MAXTRY do
begin
(* send SOH/STX *)
PutChar(Port,PacketType);
(* send packet # *)
PutChar(Port,PacketNbr);
(* send 1's complement of packet *)
PutChar(Port,255-PacketNbr);
(* send data *)
CheckSum := 0;
for i := 0 to PacketSize - 1 do
begin
PutChar(Port,Buffer[i]);
(* update checksum *)
if NCGbyte<>NAK then CheckSum := UpdateCRC(Buffer[i],CheckSum)
else CheckSum := CheckSum + Buffer[i];
(* don't overun TX buffer *)
if (i mod 32) = 0 then
while (SioTxQue(Port) >= SioBufSize-32) do SioDelay(1);
end;
{$IFDEF DEBUG}
write('<Checksum=$');
WriteHexWord(CheckSum);
write('>');
{$ENDIF}
(* send checksum *)
if NCGbyte<>NAK then
begin
(* send 2 byte CRC *)
PutChar(Port, (CheckSum shr 8) AND $00ff );
PutChar(Port, CheckSum AND $00ff );
end
else (* NCGbyte = 'C' or 'G' *)
begin
(* send one byte checksum *)
PutChar(Port, $00ff AND CheckSum );
end;
(* don't wait for ACK if 'G' *)
if NCGbyte = Ord('G') then
begin
if PacketNbr = 0 then delay(SHORT_WAIT*ONE_SECOND div 2);
TxPacket := TRUE;
exit
end;
(* read next disk buffer while waiting for ACK *)
fioPreRead;
(* wait for receivers ACK *)
Code := GetChar(Port,LONG_WAIT*ONE_SECOND);
if Code = CAN then
begin
WriteLn('Canceled by remote');
TxPacket := FALSE;
exit
end;
if Code = ACK then
begin
TxPacket := TRUE;
exit
end;
if Code <> NAK then
begin
WriteLn('Out of sync');
TxPacket := FALSE;
exit
end;
WriteLn(PacketNbr,' NAKed');
end; (* end for *)
(* can't send packet ! *)
TimeoutMsg('Retry exceeded',PacketNbr);
TxPacket := FALSE
end; (* end -- TxPacket *)
Function RxPacket(Port:Integer; (* Port # 0..3 *)
PacketNbr:Word; (* Packet # [0,1,2,...] *)
Var PacketSize:Word; (* Packet size (128 or 1024) *)
Var Buffer:BufferType; (* 1K buffer *)
NCGbyte:Byte; (* NAK, 'C', or 'G' *)
Var EOTflag:Boolean) (* EOT was received *)
:Boolean; (* success / failure *)
Var
I : Integer;
Code : Integer;
Attempt : Word;
RxPacketNbr : Word;
RxPacketNbrC : Word;
CheckSum : Word;
RxCheckSum : Word;
RxCheckSum1 : Word;
RxCheckSum2 : Word;
PacketType : Byte;
begin
PacketNbr := PacketNbr AND $00ff;
for Attempt := 1 to MAXTRY do
begin
(* wait for SOH / STX *)
Code := GetChar(Port,LONG_WAIT*ONE_SECOND);
if Code = -1 then
begin
WriteLn('Timed out waiting for sender');
RxPacket := FALSE;
exit
end;
case Code of
SOH: begin
(* 128 byte buffer incoming *)
PacketType := SOH;
PacketSize := 128
end;
STX: begin
(* 1024 byte buffer incoming *)
PacketType := STX;
PacketSize := 1024;
end;
EOT: begin
(* all packets have been sent *)
PutChar(Port,ACK);
EOTflag := TRUE;
RxPacket := TRUE;
exit
end;
CAN: begin
(* sender has canceled ! *)
SayError(Port,'Canceled by remote');
RxPacket := FALSE;
end;
else
begin
(* error ! *)
Write('Expecting SOH/STX/EOT/CAN not $');
WriteHexByte(Code);
WriteLn;
RxPacket := FALSE;
end;
end; (* case *)
(* receive packet # *)
Code := GetChar(Port,ONE_SECOND);
if Code = -1 then
begin
TimeoutMsg('packet #',PacketNbr);
exit
end;
RxPacketNbr := $00ff and Code;
(* receive 1's complement *)
Code := GetChar(Port,ONE_SECOND);
if Code =-1 then
begin
TimeoutMsg('packet # complement',PacketNbr);
RxPacket := FALSE;
exit
end;
RxPacketNbrC := $00ff and Code;
(* receive data *)
CheckSum := 0;
for i := 0 to PacketSize - 1 do
begin
Code := GetChar(Port,ONE_SECOND);
if Code = -1 then
begin
TimeoutMsg('data',PacketNbr);
RxPacket := FALSE;
exit
end;
Buffer[i] := Code;
(* compute CRC or checksum *)
if NCGbyte <> NAK
then CheckSum := UpdateCRC(Code,CheckSum)
else CheckSum := (CheckSum + Code) AND $00ff;
end;
(* receive CRC/checksum *)
if NCGbyte<>NAK then
begin
(* receive 2 byte CRC *)
Code := GetChar(Port,ONE_SECOND);
if Code =-1 then
begin
TimeoutMsg('1st CRC byte',PacketNbr);
RxPacket := FALSE;
exit
end;
RxCheckSum1 := Code AND $00ff;
Code := GetChar(Port,ONE_SECOND);
if Code =-1 then
begin
TimeoutMsg('2nd CRC byte',PacketNbr);
RxPacket := FALSE;
exit
end;
RxCheckSum2 := Code AND $00ff;
RxCheckSum := (RxCheckSum1 SHL 8) OR RxCheckSum2;
end
else
begin
(* receive one byte checksum *)
Code := GetChar(Port,ONE_SECOND);
if Code = -1 then
begin
TimeoutMsg('checksum',PacketNbr);
RxPacket := FALSE;
exit
end;
RxCheckSum := Code AND $00ff;
end;
(* don't send ACK if 'G' *)
if NCGbyte = Ord('G') then
begin
RxPacket := TRUE;
exit
end;
(* packet # and checksum OK ? *)
if (RxCheckSum=CheckSum) and (RxPacketNbr=PacketNbr) then
begin
(* ACK the packet *)
PutChar(Port,ACK);
RxPacket := TRUE;
exit
end;
(* bad packet *)
{$IFDEF DEBUG}
write('<Checksum: Received=$');
WriteHexWord(RxCheckSum);
write(', Computed=$');
WriteHexWord(CheckSum);
write('> ');
{$ENDIF}
WriteIntMsg('NAKing packet ',PacketNbr);
PutChar(Port,NAK)
end;
(* can't receive packet *)
TimeoutMsg('NAK retry exceeded',PacketNbr);
RxPacket := FALSE
end; (* end -- RxPacket *)
Function TxStartup(Port:Integer;
Var NCGbyte:Byte):Boolean;
Label 999;
Var
Code : Integer;
I : Integer;
Result : Boolean;
Begin
(* clear Rx buffer *)
Code := SioRxFlush(Port);
(* wait for receivers start up NAK or 'C' *)
for i := 1 to LIMIT do
begin
if KeyPressed then
begin
SayError(Port,'Aborted by user');
Result := FALSE;
Goto 999
end;
Code := GetChar(Port,ONE_SECOND);
if Code <> -1 then
begin
(* received a byte *)
if Code = NAK then
begin
NCGbyte := NAK;
Result := TRUE;
Goto 999
end;
if Code = Ord('C') then
begin
NCGbyte := Ord('C');
Result := TRUE;
Goto 999
end;
if Code = Ord('G') then
begin
NCGbyte := Ord('G');
Result := TRUE;
Goto 999
end
end
end;
(* no response *)
WriteMsg('No response from receiver');
TxStartup := FALSE;
999:
TxStartup := Result;
{$IFDEF DEBUG}
write('<TxStartup ');
if Result then writeln('successfull>')
else writeln('fails>');
{$ENDIF}
end; (* end -- TxStartup *)
Function RxStartup(Port:Integer;
Var NCGbyte:Byte)
: Boolean;
Label 999;
Var
I : Integer;
Code : Integer;
Result : Boolean;
Begin
(* clear Rx buffer *)
Code := SioRxFlush(Port);
(* Send NAKs or 'C's *)
for I := 1 to LIMIT do
begin
if KeyPressed then
begin
SayError(Port,'Canceled by user');
Result := FALSE;
Goto 999
end;
(* stop attempting CRC after 1st 4 tries *)
if (NCGbyte<>NAK) and (i=5) then NCGbyte := NAK;
(* tell sender that I am ready to receive *)
PutChar(Port,NCGbyte);
Code := GetChar(Port,ONE_SECOND);
if Code <> -1 then
begin
(* no error -- must be incoming byte -- push byte back onto queue ! *)
Code := SioUnGetc(Port,Code);
Result := TRUE;
Goto 999
end;
end; (* for i *)
(* no response *)
WriteMsg('No response from sender');
Result := FALSE;
999:
RxStartup := Result;
{$IFDEF DEBUG}
write('<RxStartup ');
if Result then writeln('successfull>')
else writeln('fails>');
{$ENDIF}
end; (* end -- RxStartup *)
Function TxEOT(Port:Integer):Boolean;
Var
I : Integer;
Code : Integer;
Begin
for I := 0 to 10 do
begin
PutChar(Port,EOT);
(* await response *)
Code := GetChar(Port,ONE_SECOND);
if Code = ACK then
begin
TxEOT := TRUE;
exit
end
end; (* end -- for I) *)
TxEOT := FALSE
end; (* end -- TxEOT *)
end.